<template>
    <div>
        <!-- <div class="list-picture" v-if="uploadFiles.length > 0"></div> -->
        <div @click.native="hanldeClick" class="upload_container">
            <input  name="请上传文件" type="file" ref="uploadRef"   @change="handleChange" 
            :multiple="multiple" :accept="accept"/>
        </div>

        <div>
            <el-button @click="handleUpload()" type="primary">开始上传</el-button>
        </div>

        <div>
            <span ref="uploadResultRef"></span>
        </div>
        <div>md5Value:{{fileSparkMD5}}</div>

        <!-- {{fileChuncks}} -->
        <!-- <el-upload>
            <el-button type="primary">Click to upload</el-button>
        </el-upload> -->
    </div>
    
</template>
<script setup>
import { ref,onMounted } from 'vue'
import { ElMessage, } from 'element-plus'
import SparkMD5 from 'spark-md5';
import { makePostRequest } from '../../http/index';
defineProps({
    multiple:{
        type:Boolean,
        default:true
    },
    accept:{
        type:Array,
        default:[]
    }
})

const fileInput = ref(null)
const uploadRef = ref();
const uploadResultRef = ref(null); //上传结果展示
const uploadFiles = ref([]); //已上传的文件
const fileSparkMD5 = ref([]); //文件MD5 唯一标识
const fileChuncks = ref([]); // 文件分片list
const chunckSize = ref(1*1024*1024); //每一个片的大小
const promiseArr = []; // 分片上传promise集合
const isUploadChuncks = ref([]); // 返回 [1,1,1,0,0,1] 格式数组(这里需要服务端返回的值是按照索引正序排列),标识对应下标上传状态 已上传：1 ，未上传：0
const uploadProgress = ref(0); //上传进度
const uploadQuantity = ref(0); //总上传数量


onMounted(() => {
    const fileInput = uploadRef.value;
})

const hanldeClick = () => {
    // const fileInput = uploadRef.value;
    // fileInput.click();
}

const handleChange = (file) => {
    // const fileInput = uploadRef.value;
    // fileInput.click();
    
}

//检测文件是否上传过，
const checkFile = async (md5) => {
    const data = await makePostRequest('http://127.0.0.1:9000/checkChuncks', {md5});
    if (data.length === 0) {
        return false;
    }
    const {file_hash:fileHash,chunck_total_number:chunckTotal} = data[0];
    if(fileHash === md5) {
        const newArr = new Array(Number(chunckTotal)).fill(0);
        const chunckNumberArr = data.map(item => item.chunck_number);
        chunckNumberArr.forEach((item,index) => {
            newArr[item] = 1
        });
        isUploadChuncks.value = [...newArr];
        return true;
    }else {
        return false;
    }
}

const handleUpload = async () => {
    const fileInput = uploadRef.value;
    const file = fileInput.files[0];
    if (!file) {
        ElMessage({message:'请选择文件',type:'warning'});
        return
    } // 没有选择文件

    //循环计算文件MD5
    const fileArr = fileInput.files;
    for(let i = 0; i < fileArr.length; i++){
        // 计算文件MD5
        const data = await getFileMD5(fileArr[i]);
        fileSparkMD5.value.push({md5Value:data,fileKey:fileArr[i].name});
        // 继续进行分片
        sliceFile(fileArr[i]);
    }

    //检测文件是否已上传过
    const {md5Value} = fileSparkMD5.value[0];   
    const isFlag = await checkFile(md5Value); //是否上传过
    if(isFlag) {
        const hasEmptyChunk = isUploadChuncks.value.findIndex(item => item === 0);
        //上传过,并且已经完整上传，直接提示上传成功（秒传）
        if(hasEmptyChunk === -1) {
            ElMessage({message:'上传成功',type:'success'});
            return;
        }else {
            //上传缺失的分片文件
            for(let k = 0; k < isUploadChuncks.value.length; k++) {
                if(isUploadChuncks.value[k] !== 1) {
                    const {md5Value,fileKey} = fileSparkMD5.value[0]; //单文件处理，多文件需要遍历匹配对应的文件
                    let data = new FormData();
                    data.append('totalNumber',fileChuncks.value.length);
                    data.append("chunkSize",chunckSize.value);
                    data.append("chunckNumber",k);
                    data.append('md5',md5Value);
                    data.append('name',fileKey);
                    data.append('file',new File([fileChuncks.value[k].fileChuncks],fileKey))
                    httpRequest(data,k,fileChuncks.value.length);
                }
            }
        }
    }else {
        //未上传，执行完整上传逻辑
        fileChuncks.value.forEach((e, i)=>{
            const {md5Value,fileKey} = fileSparkMD5.value.find(item => item.fileKey === e.fileName);
            let data = new FormData();
            data.append('totalNumber',fileChuncks.value.length);
            data.append("chunkSize",chunckSize.value);
            data.append("chunckNumber",i);
            data.append('md5',md5Value);
            data.append('name',fileKey);
            data.append('file',new File([e.fileChuncks],fileKey))
            httpRequest(data,i,fileChuncks.value.length);
        })
    }

    let uploadResult = uploadResultRef.value;
    Promise.all(promiseArr).then((e)=>{
        console.log(e, '========')
        //处理上传成功逻辑
        uploadResultRef.value.innerHTML = '上传成功';
        //fileChuncks.value.length 文件切片的总长度，这里只做单个的演示
        //所有上传完毕，开启合并文件操作
        mergeFile(fileSparkMD5.value,fileChuncks.value.length);
    }).catch(e=>{
        console.log(e)
        ElMessage({message:'文件未上传完整，请继续上传',type:'success'});
        uploadResultRef.value.innerHTML = '上传失败';
    })
}

//file：文件内容，nowChunck:当前切片的排序，totalChunck:总的切片数量
const httpRequest = (file,nowChunck,totalChunck) => {
    const curPormise = new Promise((resolve,reject)=>{
        let uploadResult = uploadResultRef.value;
        let xhr = new XMLHttpRequest();
        // 小文件处理上传进度
        // xhr.upload.onprogress = function(event) {
        //     let percent = 100 * event.loaded / event.total;
        //     uploadResult.innerHTML='上传进度：' + percent + '%';
        // };
        // 当上传完成时调用
        xhr.onload = function() {
            if (xhr.status === 200) {
                // uploadResult.innerHTML = '上传成功'+ xhr.responseText;
                //大文件上传进度
                uploadQuantity.value ++;
                uploadProgress.value = uploadQuantity.value / totalChunck * 100;
                uploadResultRef.value.innerHTML='上传进度：' + uploadProgress.value + '%';
                return resolve(nowChunck)
            }
        }
        xhr.onerror = function(e) {
            // uploadResult.innerHTML = '上传失败';
            return reject(e)
        }
        // 发送请求
        xhr.open('POST', 'http://127.0.0.1:9000/upload', true);
        xhr.send(file);
    })
    promiseArr.push(curPormise);
}

const getFileMD5 = (file) => {
    return new Promise((resolve, reject) => {
        // const spark = new SparkMD5.ArrayBuffer();
        const fileReader = new FileReader();
        fileReader.onload = (e) =>{
            const fileMd5 = SparkMD5.ArrayBuffer.hash(e.target.result)
            resolve(fileMd5)
        }
        fileReader.onerror = (e) =>{
            reject('文件读取失败',e)
        }
        fileReader.readAsArrayBuffer(file);
    })
}

const sliceFile = (file) => {
    //文件分片之后的集合
    const chuncks = [];
    let start = 0 ;
    let end;
    while(start < file.size) {
        end = Math.min(start + chunckSize.value,file.size);
        //slice 截取文件字节
        chuncks.push({fileChuncks:file.slice(start,end),fileName:file.name}); 
        start = end;
    }
    fileChuncks.value = [...chuncks];
}

const mergeFile = async (fileInfo,chunckTotal) => {
    const { md5Value,fileKey }  = fileInfo[0];
    const params = {
        totalNumber:chunckTotal,
        md5:md5Value,
        name:fileKey
    }
    const response = await makePostRequest('http://127.0.0.1:9000/merge', params);
    ElMessage({message:'上传成功',type:'success'});
}

</script>
